package com.iot08.api.service;


import com.iot08.api.config.sms.AliYunSmsConfig;
import com.iot08.api.config.sms.JdySdkSmsClientConfig;
import com.iot08.api.constant.Constant;
import com.iot08.api.service.mail.EmailService;
import com.iot08.api.service.sms.IProviderJdySmsService;
import com.iot08.api.service.sms.IProviderSmsService;
import com.iot08.api.vo.request.SmsReqBodyFormVo;
import com.iot08.common.config.redis.RedisService;
import com.iot08.common.entity.app.Account;
import com.iot08.common.entity.app.sms.SendSmsResponseWrapper;
import com.iot08.common.entity.app.sms.SmsCode;
import com.iot08.common.utils.MessageUtils;
import com.iot08.common.utils.response.ResponseEnum;
import com.iot08.common.utils.response.ResponseMap;
import com.jdcloud.sdk.service.sms.model.BatchSendResponse;
import com.jdcloud.sdk.service.sms.model.BatchSendResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.validation.constraints.NotNull;
import java.util.*;

/**
 * @description:验证码发送服务
 * @author: chenwenjie
 * @date: 2023/6/29 10:22
 * @param:
 * @return:
 **/
@Slf4j
@RequiredArgsConstructor
@Service
public class SmsService {

    private final AliYunSmsConfig aliYunSmsConfig;

    private final IProviderSmsService aliYunSmsServiceImpl;

    private final JdySdkSmsClientConfig jdySdkSmsClientConfig;

    private final IProviderJdySmsService jdyunSmsService;

    private final RedisService redisService;

    private final AccountService accountService;

    private final EmailService emailService;

    /**
     * @description 发送不同模板类型的短信
     * @author cwj
     * @param [phoneNum, templateType]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/11/18 11:26
     **/
    public ResponseMap sendCode(SmsReqBodyFormVo vo) {
        ResponseMap fail = checkEamil(vo);
        if (fail != null) return fail;
        //检查电话号码是否存在
        ResponseMap STATUS400 = checkPhoneExists(vo);
        if (STATUS400 != null) return STATUS400;
        Map<String,Object> map;
        //检查短信认证的短信服务是否开启及短信认证码是否发送频繁
        if(ObjectUtils.isEmpty(vo.getSendCodeWay()) || Integer.valueOf(0).equals(vo.getSendCodeWay())) {
            map = checkMessage(vo.getPhone());
        } else {
            //邮箱发送
            map = checkMessageByEamil(vo.getEmail());
        }
        try {
            boolean isOk = (boolean) map.get("success");
            if(isOk){
                if(ObjectUtils.isEmpty(vo.getSendCodeWay()) || Integer.valueOf(0).equals(vo.getSendCodeWay())) {
                    //按照指定短信模板发送短信息
                    //return sendMessageByTemplate(vo.getPhone(), aliYunSmsConfig.getTemplate(vo.getTemplateType()));
                    return sendJdyMessageByTemplate(vo.getPhone(), jdySdkSmsClientConfig.getTemplate(vo.getTemplateType()));
                } else {
                    return sendEmailMessage(vo.getEmail());
                }
            }else{
                return  ResponseMap.fail(map.get("msg").toString());
            }
        } catch (Exception e) {
            log.info("验证码发送异常", e);
            return ResponseMap.fail(MessageUtils.getLocale("API.request.ResponseMsg.SmsSendFail"));
        }
    }

    /**
     * @description 检查邮箱号是否合规
     * @author cwj
     * @param [vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/5/7 14:59
     **/
    private ResponseMap checkEamil(SmsReqBodyFormVo vo) {
        if(!ObjectUtils.isEmpty(vo.getSendCodeWay()) && Integer.valueOf(1).equals(vo.getSendCodeWay())){
            //检查邮箱号是否符合存在且符合要求
            if(StringUtils.isEmpty(vo.getEmail())){
                return ResponseMap.fail("参数缺失，缺少邮箱号");
            }
            //检查邮箱格式
            if(!vo.getEmail().matches("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")){
                return ResponseMap.fail("参数错误，邮箱号的格式不对");
            }
            if (Integer.valueOf(0).equals(vo.getTemplateType())) {
                //按验证码的模式检查邮箱号在系统中的存在情况
                boolean isExists = accountService.checkAccountExistsByEamil(vo.getEmail());
                if(isExists) {
                    return ResponseMap.fail("输入的邮箱号系统中已存在，请更换其他邮箱");
                }
            } else if(Integer.valueOf(1).equals(vo.getTemplateType())) {
                Account account = accountService.queryAccountByPhone(vo.getPhone(), vo.getCountry_code());
                if(ObjectUtils.isEmpty(account)) {
                    return ResponseMap.fail("账户已注销或不存在，无法发送验证码");
                } else if (ObjectUtils.isEmpty(account.getEmail())) {
                    return ResponseMap.fail("账户未绑定邮箱号，无法发送验证码");
                } else if(!vo.getEmail().equals(account.getEmail())) {
                    return ResponseMap.fail("账户绑定邮箱号与输入邮箱号不一致，无法发送验证码");
                }
            }
        }
        return null;
    }

    /**
     * @description 检查电话是否存在，注册时，电话号码要求未注册，
     * @author cwj
     * @param [vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/12/2 13:24
     **/
    private ResponseMap checkPhoneExists(SmsReqBodyFormVo vo) {
        boolean isExists = accountService.chcekAccountExists(vo.getPhone(), vo.getCountry_code());
        if (vo.getTemplateType() == 0) {
            if (isExists) {
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.ResponseMsg.Register.UserExists");
            }
        } else if (vo.getTemplateType() == 1 && !isExists) {
            return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.ResponseMsg.ResetPassword.UserNotExists");
        }
        return null;
    }


    /**
     * @description 发送通知消息
     * @author cwj
     * @param [phone, templateType, nickName]
     * @return java.lang.String
     * @date @time 2024/8/29 9:50
     **/
    public boolean sendNotify(String phoneNum, Integer templateType,String templateVariable,String templateVariableName) {
        try {
            //获取模板
            Map<String, String> param = new HashMap<>();
            if(StringUtils.isNotEmpty(templateVariableName) && StringUtils.isNotEmpty(templateVariable)) {
                param.put(templateVariableName,templateVariable);
            }
            //发送通知信息
            SendSmsResponseWrapper smsData = aliYunSmsServiceImpl.send(phoneNum,param, aliYunSmsConfig.getTemplate(templateType));
            if(smsData.isSuccess()){
              return true;
            }else{
                log.error("短信发生失败的原因："+smsData.getMessage());
                return false;
            }
        }catch (Exception e){
            log.error("短信发送时出现异常，message:{}",e.getMessage());
            return false;
        }
    }


    /**
     * @description 获取缓存验证码
     * @author cwj
     * @param [cacheKey]
     * @return java.lang.String
     * @date @time 2025/3/20 10:06
     **/
    public String cacheCode(String cacheKey) {
        return redisService.get(cacheKey);
    }

    public Boolean validateCode(String cacheKey, String code) {
        String cacheCode = cacheCode(cacheKey);
        if (StringUtils.isBlank(cacheCode)) {
            //throw new ServiceException("验证码已失效");
            return false;
        }

        boolean success = StringUtils.equals(cacheCode, code);
        if (success) {
            //redisService.deleteObject(cacheKey);
            redisService.del(cacheKey);
        }
        return success;
    }

    /**
     * @description: 检查短信认证的短信服务是否开启及短信认证码是否发送频繁
     * @author: chenwenjie
     * @date: 2023/12/15 10:44
     * @param: [mobile]
     * @return: void
     **/
    private Map<String,Object> checkMessage(String phone) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        String hasExistsKey = Constant.SMS_KEY_PREFIX + phone;
        if (this.redisService.exists(hasExistsKey)) {
            map.put("success", false);
            map.put("msg", MessageUtils.getLocale("API.request.ResponseMsg.SmsSendFrequently"));
            return map;
        }
        if (BooleanUtils.isFalse(aliYunSmsConfig.getEnable())) {
            map.put("success",false);
            map.put("msg",MessageUtils.getLocale("API.request.ResponseMsg.SmsPauseService"));
            return map;
        }
        if (aliYunSmsConfig.getLimitSendCount() != null && aliYunSmsConfig.getLimitSendCount() > 0) {
            String useCount = redisService.get(Constant.SMS_LIMIT_COUNT_KEY_PREFIX + phone);
            if (useCount != null && Integer.parseInt(useCount) >= aliYunSmsConfig.getLimitSendCount()) {
                map.put("success", false);
                map.put("msg", MessageUtils.getLocale("API.request.ResponseMsg.SmsSendTooFrequently"));
                return map;
            }
        }
        return map;
    }


    /**
     * @description 检查短信是否频繁发送
     * @author cwj
     * @param [email]
     * @return java.util.Map<java.lang.String,java.lang.Object>
     * @date @time 2025/5/7 16:54
     **/
    private Map<String,Object> checkMessageByEamil(String email) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        String hasExistsKey = Constant.SMS_KEY_PREFIX + email;
        if (this.redisService.exists(hasExistsKey)) {
            map.put("success", false);
            map.put("msg", "验证码发送太频繁，一分钟只能发送一次短信");
            return map;
        }
        if (BooleanUtils.isFalse(aliYunSmsConfig.getEnable())) {
            map.put("success",false);
            map.put("msg","暂停发送验证码");
            return map;
        }
        if (aliYunSmsConfig.getLimitSendCount() != null && aliYunSmsConfig.getLimitSendCount() > 0) {
            String useCount = redisService.get(Constant.SMS_LIMIT_COUNT_KEY_PREFIX + email);
            if (useCount != null && Integer.parseInt(useCount) >= aliYunSmsConfig.getLimitSendCount()) {
                map.put("success", false);
                map.put("msg","发送验证码太频繁");
                return map;
            }
        }
        return map;
    }
    
    /**
     * @description: 按照指定短信息模板发送短信
     * @author: chenwenjie
     * @date: 2023/12/15 10:47
     * @param: [mobile, map]
     * @return: java.lang.String
     **/
    @NotNull
    private ResponseMap sendMessageByTemplate(String phone, Map<String,String> map) throws Exception {
        String uuid = UUID.randomUUID().toString();
        String code = RandomStringUtils.random(6,false,true);
        SmsCode smsCode = new SmsCode(code);
        //发送短信信息
        SendSmsResponseWrapper smsData = aliYunSmsServiceImpl.send(phone,smsCode,map);
        if(smsData.isSuccess()){
            ResponseMap res = ResponseMap.success();
            //一分钟内只能发送一次
            this.redisService.setex(Constant.SMS_KEY_PREFIX + phone, 60, phone);
            //缓存验证码，保存时间是5分钟，用户必须5分钟内使用验证码
            redisService.setex(Constant.SMS_KEY_PREFIX + uuid + phone,  5*60,code);
            //设置短信发送5分钟内最大发送次数，缓存过期时间是5分钟，超过5分钟则过期，过期了则可重新创建缓存对象
            String maxLimitKey = Constant.SMS_LIMIT_COUNT_KEY_PREFIX + phone;
            if(!redisService.exists(maxLimitKey)){
                redisService.setex(maxLimitKey,  5*60,"0");
            }
            //最大限制次数加1
            int maxLimit = Integer.parseInt(redisService.get(maxLimitKey))+1;
            redisService.del(maxLimitKey);
            redisService.setex(maxLimitKey,5*60, Integer.toString(maxLimit));
            //redisService.incr(maxLimitKey,1);
            res.put("uuid",uuid);
            return res;
        }else{
            log.error("短信发生失败的原因："+smsData.getMessage());
            return ResponseMap.fail(MessageUtils.getLocale("API.request.ResponseMsg.SmsSendFail"));
        }
    }

    /**
     * @description 发送京东短信服务
     * @author cwj
     * @param [phone, map]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/6/17 11:13
     **/
    /**
     * @description 发送京东短信
     * @author cwj
     * @param [phone, map]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/6/16 17:16
     **/
    @NotNull
    private ResponseMap sendJdyMessageByTemplate(String phone, Map<String,String> map) {
        String uuid = UUID.randomUUID().toString();
        String code = RandomStringUtils.random(6,false,true);
        List<String> phoneList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        phoneList.add(phone);
        params.add(code);
        BatchSendResponse response = jdyunSmsService.send(phoneList,params,map);
        //log.info("发送的结果：{}",response);
        if(!ObjectUtils.isEmpty(response)) {
            BatchSendResult result = response.getResult();
            if (!ObjectUtils.isEmpty(result) && !ObjectUtils.isEmpty(result.getCode()) && !ObjectUtils.isEmpty(result.getStatus()) && result.getStatus() && result.getCode().equals(11520000L)) {
                ResponseMap res = ResponseMap.success();
                //一分钟内只能发送一次
                this.redisService.setex(Constant.SMS_KEY_PREFIX + phone, 60, phone);
                //缓存验证码，保存时间是5分钟，用户必须5分钟内使用验证码
                redisService.setex(Constant.SMS_KEY_PREFIX + uuid + phone,  5*60,code);
                //设置短信发送5分钟内最大发送次数，缓存过期时间是5分钟，超过5分钟则过期，过期了则可重新创建缓存对象
                String maxLimitKey = Constant.SMS_LIMIT_COUNT_KEY_PREFIX + phone;
                if(!redisService.exists(maxLimitKey)){
                    redisService.setex(maxLimitKey,  5*60,"0");
                }
                //最大限制次数加1
                int maxLimit = Integer.parseInt(redisService.get(maxLimitKey))+1;
                redisService.del(maxLimitKey);
                redisService.setex(maxLimitKey,5*60, Integer.toString(maxLimit));
                //redisService.incr(maxLimitKey,1);
                res.put("uuid",uuid);
                return res;
            }else{
                log.error("短信发生失败的原因：{}",response);
                return ResponseMap.fail(MessageUtils.getLocale("API.request.ResponseMsg.SmsSendFail"));
            }
        }
        return ResponseMap.success();
    }

    /**
     * @description
     * @author cwj
     * @param [email, phone]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/5/7 15:09
     **/
    public ResponseMap sendEmailMessage(String email){
        String uuid = UUID.randomUUID().toString();
        String code = RandomStringUtils.random(6,false,true);
        emailService.sendVerifyCode(email,code);
        ResponseMap res = ResponseMap.success();
        //一分钟内只能发送一次
        this.redisService.setex(Constant.SMS_KEY_PREFIX + email, 60, email);
        //缓存验证码，保存时间是5分钟，用户必须5分钟内使用验证码
        redisService.setex(Constant.SMS_KEY_PREFIX + uuid + email,  5*60,code);
        //设置短信发送5分钟内最大发送次数，缓存过期时间是5分钟，超过5分钟则过期，过期了则可重新创建缓存对象
        String maxLimitKey = Constant.SMS_LIMIT_COUNT_KEY_PREFIX + email;
        if(!redisService.exists(maxLimitKey)){
            redisService.setex(maxLimitKey,  5*60,"0");
        }
        //最大限制次数加1
        int maxLimit = Integer.parseInt(redisService.get(maxLimitKey))+1;
        redisService.del(maxLimitKey);
        redisService.setex(maxLimitKey,5*60, Integer.toString(maxLimit));
        //redisService.incr(maxLimitKey,1);
        res.put("uuid",uuid);
        return res;
    }

}
